
// this is what's gonna receive the gamepad data
struct DIGAMEPADSTATE {
    LONG lx, ly;		// left analog
    LONG rx, ry;		// right analog
	DWORD dpad;			// D-pad
	BYTE buttons[16];	// buttons
};

// define a data format that's a better match to gamepads than DIJOYSTICK2 (which blows)
DIOBJECTDATAFORMAT GamepadObjectFormats[] = {
	// right analog?
    { &GUID_XAxis, FIELD_OFFSET( DIGAMEPADSTATE, lx ), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
    { &GUID_YAxis, FIELD_OFFSET( DIGAMEPADSTATE, ly ), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },		

	// left analog?
	{ null, FIELD_OFFSET( DIGAMEPADSTATE, rx ), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },		
	{ null, FIELD_OFFSET( DIGAMEPADSTATE, ry ), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },

	// d-pad?
	{ &GUID_POV, FIELD_OFFSET( DIGAMEPADSTATE, dpad ), DIDFT_POV | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },

	// many buttons?
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[0]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[1]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[2]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[3]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[4]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[5]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[6]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[7]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[8]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[9]  ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[10] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[11] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[12] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[13] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[14] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ &GUID_Button, FIELD_OFFSET( DIGAMEPADSTATE, buttons[15] ), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
};

#define numGamepadObjects ( sizeof(GamepadObjectFormats) / sizeof(GamepadObjectFormats[0]) )

DIDATAFORMAT GamepadDataFormat = {
    sizeof( DIDATAFORMAT ),
    sizeof( DIOBJECTDATAFORMAT ),
    DIDF_ABSAXIS,
    sizeof( DIGAMEPADSTATE ),
    numGamepadObjects,
    GamepadObjectFormats
};
//


struct Gamepad {
	bool exists;
	DIGAMEPADSTATE state;

	LPDIRECTINPUT8		 DirectInputObject;		// pointer back to the directInput object
	LPDIRECTINPUTDEVICE8 DirectInputGamepad;	// pointer back to our OWN directInput interface?

	Gamepad ():
		DirectInputObject	(null),
		DirectInputGamepad	(null),
		exists				(false)
	{}
	//

	void setup (HWND window, LPDIRECTINPUT8 _DirectInputObject, GUID guid) {
		shutdown();
		DirectInputObject = _DirectInputObject;
		DirectInputObject->CreateDevice			(guid, &DirectInputGamepad, NULL);
		DirectInputGamepad->SetDataFormat		(&GamepadDataFormat);
		DirectInputGamepad->SetCooperativeLevel	(window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
		exists = true;
	}
	//

	void update () {
		if (DirectInputGamepad != null) {
			DirectInputGamepad->Acquire();
			DirectInputGamepad->GetDeviceState( sizeof(DIGAMEPADSTATE), &state );
		}
	}
	//

	void shutdown () {
		if (DirectInputGamepad != null) {
			DirectInputGamepad->Unacquire();
			DirectInputGamepad->Release();
		}
		exists = false;
	}
	//

	void config () {
		// outside:
		// enumerate the objects
		// map objects to bindings


		// I want a way to pass in a ref to a specific object
	}
	//

};
//


struct Keyboard {
	BYTE state[256]; // to test a key look at keys[#] & 0x80

	LPDIRECTINPUT8		 DirectInputObject;
	LPDIRECTINPUTDEVICE8 DirectInputKeyboard;

	Keyboard ():
		DirectInputObject	(null),
		DirectInputKeyboard	(null)
	{}
	//

	void setup (HWND window, LPDIRECTINPUT8 _DirectInputObject) {
		DirectInputObject = _DirectInputObject;
		DirectInputObject->CreateDevice			(GUID_SysKeyboard, &DirectInputKeyboard, NULL);
		DirectInputKeyboard->SetDataFormat		(&c_dfDIKeyboard);
		DirectInputKeyboard->SetCooperativeLevel(window, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE|DISCL_NOWINKEY);
	}
	//

	void update () {
		if (DirectInputKeyboard != null) {
			DirectInputKeyboard->Acquire();
			DirectInputKeyboard->GetDeviceState( sizeof(state), state );
		}
	}
	//

	void shutdown () {
		if (DirectInputKeyboard != null) {
			DirectInputKeyboard->Unacquire();
			DirectInputKeyboard->Release();
		}
	}
	//
};
//


struct Mouse {
	DIMOUSESTATE2 state; // lx ly lz, rgbButtons[0-7] & 0x80

	LPDIRECTINPUT8		 DirectInputObject;
	LPDIRECTINPUTDEVICE8 DirectInputMouse;

	Mouse ():
		DirectInputObject	(null),
		DirectInputMouse	(null)
	{}
	//

	void setup (HWND window, LPDIRECTINPUT8 _DirectInputObject) {
		DirectInputObject = _DirectInputObject;
		DirectInputObject->CreateDevice			(GUID_SysMouse, &DirectInputMouse, NULL);
		DirectInputMouse->SetDataFormat			(&c_dfDIMouse2);
		DirectInputMouse->SetCooperativeLevel	(window, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
	}
	//

	void update () {
		if (DirectInputMouse != null) {
			DirectInputMouse->Acquire();
			DirectInputMouse->GetDeviceState( sizeof(state), &state );
		}
	}
	//

	void shutdown () {
		if (DirectInputMouse != null) {
			DirectInputMouse->Unacquire();
			DirectInputMouse->Release();
		}
	}
	//
};
//
